﻿Imports Microsoft.CSharp
Imports Microsoft.VisualBasic
Imports Microsoft.Win32
Imports System
Imports System.CodeDom.Compiler
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.IO
Imports System.Security

Namespace System.Workflow.ComponentModel.Compiler
    Friend Class CompilerHelpers
        ' Methods
        Friend Shared Function CreateCodeProviderInstance(ByVal type As Type) As CodeDomProvider
            If Not CompilerHelpers.useDotNet20.HasValue Then
                CompilerHelpers.useDotNet20 = New Nullable([Of] Boolean)((type.GetConstructor(New Type() { GetType(IDictionary([Of] String, String)) }) Is Nothing))
            End If
            If (CompilerHelpers.useDotNet20 = True) Then
                If (type Is GetType(CSharpCodeProvider)) Then
                    Return New CSharpCodeProvider
                End If
                If (type Is GetType(VBCodeProvider)) Then
                    Return New VBCodeProvider
                End If
                Return DirectCast(Activator.CreateInstance(type), CodeDomProvider)
            End If
            Dim dictionary As New Dictionary([Of] String, String)
            dictionary.Add("CompilerVersion", CompilerHelpers.VersionNumber)
            Return DirectCast(Activator.CreateInstance(type, New Object() { dictionary }), CodeDomProvider)
        End Function

        Friend Shared Function GetCodeDomProvider(ByVal language As SupportedLanguages) As CodeDomProvider
            If (language = SupportedLanguages.CSharp) Then
                Return CompilerHelpers.CSharpProvider
            End If
            Return CompilerHelpers.VBProvider
        End Function

        Friend Shared Function GetSupportedLanguage(ByVal serviceProvider As IServiceProvider) As SupportedLanguages
            Dim cSharp As SupportedLanguages = SupportedLanguages.CSharp
            Dim service As IWorkflowCompilerOptionsService = [TryCast](serviceProvider.GetService(GetType(IWorkflowCompilerOptionsService)),IWorkflowCompilerOptionsService)
            If (Not service Is Nothing) Then
                cSharp = CompilerHelpers.GetSupportedLanguage(service.Language)
            End If
            Return cSharp
        End Function

        Friend Shared Function GetSupportedLanguage(ByVal language As String) As SupportedLanguages
            Dim cSharp As SupportedLanguages = SupportedLanguages.CSharp
            If (String.IsNullOrEmpty(language) OrElse ((String.Compare(language, "VB", StringComparison.OrdinalIgnoreCase) <> 0) AndAlso (String.Compare(language, "VisualBasic", StringComparison.OrdinalIgnoreCase) <> 0))) Then
                Return cSharp
            End If
            Return SupportedLanguages.VB
        End Function

        Friend Shared Function GetSupportedLanguage(ByVal workflowCompilerOptions As IWorkflowCompilerOptionsService) As SupportedLanguages
            Dim cSharp As SupportedLanguages = SupportedLanguages.CSharp
            If (Not workflowCompilerOptions Is Nothing) Then
                cSharp = CompilerHelpers.GetSupportedLanguage(workflowCompilerOptions.Language)
            End If
            Return cSharp
        End Function

        Private Shared Function IsNetFx35Installed() As Boolean
            Try 
                Dim key As RegistryKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\Microsoft\NET Framework Setup\NDP")
                If (key Is Nothing) Then
                    Return False
                End If
                Dim subKeyNames As String() = key.GetSubKeyNames
                If (subKeyNames Is Nothing) Then
                    Return False
                End If
                Dim str As String
                For Each str In subKeyNames
                    If str.StartsWith("v3.5", StringComparison.OrdinalIgnoreCase) Then
                        Return True
                    End If
                Next
            Catch exception1 As Win32Exception
            Catch exception2 As SecurityException
            Catch exception3 As UnauthorizedAccessException
            Catch exception4 As IOException
            End Try
            Return False
        End Function


        ' Properties
        Private Shared ReadOnly Property CSharpProvider As CodeDomProvider
            Get
                If (CompilerHelpers.csharpProvider Is Nothing) Then
                    CompilerHelpers.csharpProvider = CompilerHelpers.CreateCodeProviderInstance(GetType(CSharpCodeProvider))
                End If
                Return CompilerHelpers.csharpProvider
            End Get
        End Property

        Private Shared ReadOnly Property VBProvider As CodeDomProvider
            Get
                If (CompilerHelpers.vbProvider Is Nothing) Then
                    CompilerHelpers.vbProvider = CompilerHelpers.CreateCodeProviderInstance(GetType(VBCodeProvider))
                End If
                Return CompilerHelpers.vbProvider
            End Get
        End Property

        Private Shared ReadOnly Property VersionNumber As String
            Get
                If (CompilerHelpers.versionNumber Is Nothing) Then
                    If CompilerHelpers.IsNetFx35Installed Then
                        CompilerHelpers.versionNumber = "v3.5"
                    Else
                        CompilerHelpers.versionNumber = "v2.0"
                    End If
                End If
                Return CompilerHelpers.versionNumber
            End Get
        End Property


        ' Fields
        Private Const CompilerVersionKeyword As String = "CompilerVersion"
        Private Shared csharpProvider As CodeDomProvider = Nothing
        Private Const NDPSetupRegistryBranch As String = "SOFTWARE\Microsoft\NET Framework Setup\NDP"
        Private Shared useDotNet20 As Nullable([Of] Boolean) = Nothing
        Private Shared vbProvider As CodeDomProvider = Nothing
        Private Shared versionNumber As String = Nothing
        Private Const VersionNumber20 As String = "v2.0"
        Private Const VersionNumber35 As String = "v3.5"
    End Class
End Namespace

